package com.bjb.vr.auth.config;

import com.bjb.vr.auth.filter.CustomHeaderAuthencationFilter;
import com.bjb.vr.auth.filter.CustomLoginFilter;
import com.bjb.vr.auth.filter.CustomLogoutHandler;
import com.bjb.vr.auth.security.*;
import com.bjb.vr.common.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;


/**
 * Spring Security 配置类
 *
 * @version 1.0.0
 * @author: HuJingBo
 * @time: 2022/4/7 15:53
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${com.bjb.vr.login.enable-captcha:false}")
    private Boolean enableCaptcha;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    RequestAccessDeniedHandler accessDeniedHandler;

    @Autowired
    RequestLogoutSuccessHandler logoutSuccessHandler;

    @Autowired
    RequestAuthenticationFailureHandler authenticationFailureHandler;

    @Autowired
    RequestAuthenticationSuccessHandler authenticationSuccessHandler;

    @Autowired
    RequestAuthenticationEntryPointHandler authenticationEntryPointHandler;

    /**
     * 放行静态资源
     *
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/**.html", "/**.js", "/**.css", "/**.jpg", "/**.png", "/**.ico", "/**.jpeg", "/**.gif", "/**.svg", "/**.woff", "/**.ttf", "/**.woff2", "/**.eot");
    }

    /**
     * 认证配置项
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/api/auth/v1/captcha").permitAll()
                .antMatchers("/api/auth/v1/refreshToken").permitAll()
                .antMatchers("/api/auth/v1/queryAuthorities").permitAll()
//                .anyRequest().access("@rbacService.hasPermission(request)")
//                .anyRequest().authenticated()
                .anyRequest().permitAll()
                .and().formLogin()
                .and().logout().logoutUrl("/api/auth/v1/logout").addLogoutHandler(new CustomLogoutHandler(redisUtil)).invalidateHttpSession(true).clearAuthentication(true).logoutSuccessHandler(logoutSuccessHandler);
//                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 配置异常处理器
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(authenticationEntryPointHandler);
        // 自定义认证过滤器
        http.addFilterAt(headerAuthencationFilter(), BasicAuthenticationFilter.class);
        http.addFilterAt(customLoginFilter(), UsernamePasswordAuthenticationFilter.class);
    }

    /**
     * 自定义登录认证过滤器
     *
     * @return
     */
    @Bean
    public CustomLoginFilter customLoginFilter() throws Exception {
        CustomLoginFilter customLoginFilter = new CustomLoginFilter();
        customLoginFilter.setFilterProcessesUrl("/api/auth/v1/login");
        customLoginFilter.setRedisService(redisUtil);
        customLoginFilter.setEnableCaptcha(enableCaptcha);
        customLoginFilter.setAuthenticationManager(authenticationManagerBean());
        customLoginFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
        customLoginFilter.setAuthenticationFailureHandler(authenticationFailureHandler);
        return customLoginFilter;
    }

    /**
     * 自定义请求头认证过滤器
     */
    @Bean
    public CustomHeaderAuthencationFilter headerAuthencationFilter() throws Exception {
        CustomHeaderAuthencationFilter headerAuthencationFilter = new CustomHeaderAuthencationFilter(authenticationManagerBean());
        return headerAuthencationFilter;
    }

    /**
     * 暴露authenticationManagerBean，这样可以在其他地方获取到authenticationManagerBean
     *
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
